// 小程序无法使用eval和Function构造函数
// 目前兼容: ||  &&  (  )
export default function evaluateBooleanExpression(expression: string): boolean {
  const precedence = {
    '||': 1,
    '&&': 2,
  };

  function isHigherPrecedence(token1: string, token2: string) {
    const precendence1 = precedence[token1];
    const precendence2 = precedence[token2];
    if (precendence1 !== undefined && precendence2 !== undefined) {
      return precendence1 <= precendence2;
    }
    if (precendence1 === undefined && precendence2 !== undefined) {
      return true;
    }
    if (precendence1 !== undefined && precendence2 === undefined) {
      return false;
    }
    return false;
  }

  function applyOperator(operator: string, operand1: boolean, operand2: boolean): boolean {
    switch (operator) {
      case '||':
        return operand1 || operand2;
      case '&&':
        return operand1 && operand2;
      default:
        throw new Error(`Invalid operator: ${operator}`);
    }
  }

  function evaluateSubexpression(tokens: string[]): boolean {
    const stack: (boolean | string)[] = [];

    for (const token of tokens) {
      if (token === '(') {
        stack.push(token);
      } else if (token === ')') {
        let top = stack.pop()!;
        const subExpression: (boolean | string)[] = [];
        while (top !== '(') {
          subExpression.unshift(top);
          top = stack.pop()!;
        }
        const result = evaluateSubexpression(subExpression as string[]);
        stack.push(result);
      } else if (token in precedence) {
        while (
          stack.length > 0 &&
          stack[stack.length - 1] !== '(' &&
          isHigherPrecedence(token, stack[stack.length - 1] as string)
        ) {
          const operand1 = stack.shift() as boolean;
          const operator = stack.shift() as string;
          const operand2 = stack.shift() as boolean;
          const result = applyOperator(operator, operand1, operand2);
          stack.push(result);
        }

        stack.push(token);
      } else if (token === 'true' || token === 'false') {
        stack.push(token === 'true');
      } else {
        stack.push(token);
      }
    }

    while (stack.length > 1) {
      const operand1 = stack.shift() as boolean;
      const operator = stack.shift() as string;
      const operand2 = stack.shift() as boolean;
      const result = applyOperator(operator, operand1, operand2);
      stack.unshift(result);
    }

    return stack[0] as boolean;
  }

  const tokens = expression.split(/(\(|\)|\|\||&&|\s)/).filter(token => token.trim() !== '');
  return evaluateSubexpression(tokens);
}
